#!/usr/bin/python3
"""
Set SELinux file contexts

Sets correct SELinux labels for every file in the tree, according to the
SELinux policy installed inside the tree.

Uses the host's `setfiles` program and the tree's `file_contexts`, usually
    /etc/selinux/<SELINUXTYPE>/contexts/files/file_contexts
where <SELINUXTYPE> is the value set in /etc/selinux/config (usually "targeted"
but may also be "minimum" or "mls").

This stage may set or modify xattrs for any file inside the tree, but should
not need to create files, modify file contents, or read any files other than
`file_contexts`.

This stage should run after all other stages that create (or move) files, since
labels for newly-created files are determined by the host's SELinux policy and
may not match the tree's policy.
"""


import os
import pathlib
import subprocess
import sys

import osbuild.api


SCHEMA = """
"additionalProperties": false,
"required": ["file_contexts"],
"properties": {
  "file_contexts": {
    "type": "string",
    "description": "Path to the active SELinux policy's `file_contexts`"
  },
  "labels": {
    "type": "object",
    "description": "Labels to set of the specified files or folders",
    "items": {
      "type": "object"
    }
  },
  "force_autorelabel": {
    "type": "boolean",
    "description": "Do not use. Forces auto-relabelling on first boot.",
    "default": false
  }
}
"""


def main(tree, options):
    file_contexts = os.path.join(f"{tree}", options["file_contexts"])
    labels = options.get("labels", {})

    subprocess.run(["setfiles", "-F", "-r", f"{tree}", f"{file_contexts}", f"{tree}"], check=True)

    for path, label in labels.items():
        fullpath = os.path.join(tree, path.lstrip("/"))
        subprocess.run(["chcon", "-v", label, fullpath], check=True)

    if options.get("force_autorelabel", False):
        stamp = pathlib.Path(tree, ".autorelabel")
        stamp.touch()


if __name__ == '__main__':
    args = osbuild.api.arguments()
    r = main(args["tree"], args["options"])
    sys.exit(r)
